package com.nifostasky.main.reflex.obtainclass;

import com.nifostasky.main.reflex.template.Student;
import lombok.SneakyThrows;

import java.util.ArrayList;

/**
 * 获取class实例,三种方式
 * 1. 类型.class
 * 2. 类实例.getClass()
 * 3. Class.forName(类的权限定类名)
 */
/**
 * ** Class 对象常用方法
 * | 返回值                    | 方法说明                                                     |
 * | :------------------------ | :----------------------------------------------------------- |
 * | `<U> Class<? extends U>`  | `asSubclass(Class<U> clazz)` 强制转换该 `Class` 对象，以表示指定的 class 对象所表示的类的一个子类。 |
 * | `static Class<?>`         | `forName(String className)` 返回与带有给定字符串名的类或接口相关联的 `Class` 对象。 |
 * | `<A extends Annotation>A` | `getAnnotation(Class<A> annotationClass)` 如果存在该元素的指定类型的注解，则返回这些注解，否则返回 null。 |
 * | `Annotation[]`            | `getAnnotations()` 返回此元素上存在的所有注解。              |
 * | `ClassLoader`             | `getClassLoader()` 返回该类的类加载器。                      |
 * | `Class<?>`                | `getComponentType()` 返回表示数组组件类型的 `Class`。        |
 * | `Annotation[]`            | `getDeclaredAnnotations()` 返回直接存在于此元素上的所有注解。 |
 * | `Class<?>`                | `getDeclaringClass()` 如果此 `Class` 对象所表示的类或接口是另一个类的成员，则返回的 `Class` 对象表示该对象的声明类。 |
 * | `T[]`                     | `getEnumConstants()` 如果此 Class 对象不表示枚举类型，则返回枚举类的元素或 null。 |
 * | `Type[]`                  | `getGenericInterfaces()` 返回表示某些接口的 `Type`，这些接口由此对象所表示的类或接口直接实现。 |
 * | `Type`                    | `getGenericSuperclass()` 返回表示此 `Class` 所表示的实体（类、接口、基本类型或 void）的直接超类的 `Type`。 |
 * | `Class<?>[]`              | `getInterfaces()` 确定此对象所表示的类或接口实现的接口。     |
 * | `int`                     | `getModifiers()` 返回此类或接口以整数编码的 Java 语言修饰符。 |
 * | `String`                  | `getName()` 以 `String` 的形式返回此 `Class` 对象所表示的实体（类、接口、数组类、基本类型或 void）名称。 |
 * | `String`                  | `getCanonicalName()` 返回 Java Language Specification 中所定义的底层类的规范化名称。主要用于输出（toString）或log打印，大多数情况下和`getName()`一样，但是在内部类、数组等类型的表示形式就不同了。不能用`getCanonicalName()`去加载类对象，必须用`getName()`， |
 * | `Package`                 | `getPackage()` 获取此类的包。                                |
 * | `InputStream`             | `getResourceAsStream(String name)` 查找具有给定名称的资源。  |
 * | `String`                  | `getSimpleName()` 返回源代码中给出的底层类的简称。           |
 * | `Class<? super T>`        | `getSuperclass()` 返回表示此 `Class` 所表示的实体（类、接口、基本类型或 void）的超类的 `Class`。 |
 * | `boolean`                 | `isAnnotation()` 如果此 `Class` 对象表示一个注解类型则返回 true。 |
 * | `boolean`                 | `isAnnotationPresent(Class<? extends Annotation> annotationClass)` 如果指定类型的注解存在于此元素上，则返回 true，否则返回 false。 |
 * | `boolean`                 | `isAnonymousClass()` 当且仅当底层类是匿名类时返回 `true`。   |
 * | `boolean`                 | `isArray()` 判定此 `Class` 对象是否表示一个数组类。          |
 * | `boolean`                 | `isAssignableFrom(Class<?> cls)` 判定此 `Class` 对象所表示的类或接口与指定的 `Class` 参数所表示的类或接口是否相同，或是否是其超类或超接口。 |
 * | `boolean`                 | `isEnum()` 当且仅当该类声明为源代码中的枚举时返回 true。     |
 * | `boolean`                 | `isInstance(Object obj)` 如果obj是这个类的一个实例此方法返回true。 |
 * | `boolean`                 | `isInterface()` 判定指定的 `Class` 对象是否表示一个接口类型。 |
 * | `boolean`                 | `isLocalClass()` 当且仅当这个类是局部类此方法返回true。      |
 * | `boolean`                 | `isMemberClass()` 当且仅当底层类是成员类时返回 `true`。      |
 * | `boolean`                 | `isPrimitive()` 判定指定的 `Class` 对象是否表示一个基本类型。 |
 * | `T`                       | `newInstance()` 创建此 `Class` 对象所表示的类的一个新实例。  |
 */
public class ClassInfo {

    /**
     * 通过类型获取反射对象(class对象)
     */
    public static Class<? extends Student> getClassByType(){
        Class<Student> studentClass = Student.class;
        return studentClass;
    }

    /**
     * 通过类型获取反射对象(class对象)
     */
    public static Class<? extends Student> getClassByExample(){
        Student student = new Student();
        Class<? extends Student> studentClass = student.getClass();
        return studentClass;
    }

    /**
     * 通过类型获取反射对象(class对象)
     */
    @SneakyThrows
    public static Class<? extends Student> getClassByClasspath(){
        Class<? extends Student> studentClass = (Class<? extends Student>) Class.forName("com.nifostasky.main.reflex.template.Student");
        return studentClass;
    }

    @SneakyThrows
    public static void main(String[] args) {
//      获取class实例
        ArrayList<Object> classList = new ArrayList<>();
        classList.add(ClassInfo.getClassByType()); //根据类型获取class实例
        classList.add(ClassInfo.getClassByExample()); //根据模板获取class实例
        classList.add(ClassInfo.getClassByClasspath()); //根据路径获取class实例
        classList.stream().forEach(i ->  System.out.println(i.toString()));
//      创建对象
//        // 1.知道对象的类型(这种情况用不到反射特性,因为反射是操作未知对象的一种方法)
//        Class<Student> studentClass = (Class<Student>) ClassInfo.getClassByType();
//        Student student = studentClass.newInstance();
//        // 2. 不知道对象的类型
//        //获取反射入口对象(Class对象)
//        String classpath = "com.nifostasky.main.reflex.template.Student";
//        Class<?> aClass = Class.forName(classpath);
//        //创建对象(未知类型)
//        Object object = aClass.newInstance();
//        //获取构造器
//        aClass.con

    }
}